#pragma .h  #import <objc/Object.h> 
#pragma .h #import <appkit/graphics.h>
#pragma .h struct gFlags
#pragma .h { unsigned isRoot: 1 ;
#pragma .h   unsigned isTarget: 1 ;
#pragma .h   unsigned noDraw: 1 ; } ;
#import "Glyph.h"
#import "Terminator.h"
#import <dpsclient/psops.h>
#import <appkit/Application.h>

 
@implementation Glyph: Object
{ @public
  NXRect frame ;
  Glyph *is, *then, *ancestor ;
  // these belong as a bitstructure
  struct gFlags flags ;
  char iam[20] ;
}

- ancestor ;
{ return ancestor ;
}

- ancestor: aGlyph ;
{ return ancestor = aGlyph ;
}

-convertFromAncestor: (NXPoint *) aPnt ;
// Convert aPnt from my ancestor's coord system to 
// my own. Does nothing if I am the root
{ if(!flags.isRoot)
  { aPnt->x -= frame.origin.x ;
    aPnt->y -= frame.origin.y ;
  }
  return self ;
}


-convertFromRootGlyph: (NXPoint *) aPnt ;
// Convert aPnt from rootGlyph's coord system
// to my coord system.
{ Glyph *aGlyph ;
  aGlyph = self ;
  while(!aGlyph->flags.isRoot) 
  { aPnt->x -= aGlyph->frame.origin.x ;
    aPnt->y -= aGlyph->frame.origin.y ;
    aGlyph = aGlyph->ancestor ;
 if([aGlyph isTerminator])
 { [NXApp printf: "from oops\n"] ;
   return self ;
 }
  }
   return self ; 
}

-convertToAncestor: (NXPoint *) aPnt ;
// Convert aPnt from my coord system to that
// of my ancestor. Does nothing if I am the
// rootGlyph
{ if(!flags.isRoot)
  { aPnt->x += frame.origin.x ;
    aPnt->y += frame.origin.y ;
  }
  return self ;
}

-convertToRootGlyph: (NXPoint *) aPnt ;
// Convert aPnt from my coord system
// to that of the rootGlyph.
{ Glyph *aGlyph ;
  aGlyph = self ;
  while(!aGlyph->flags.isRoot)
  { aPnt->x += aGlyph->frame.origin.x ;
    aPnt->y += aGlyph->frame.origin.y ;
    aGlyph = aGlyph->ancestor ;
 if([aGlyph isTerminator])
 { [NXApp printf: "to oops\n"] ;
   return self ;
 }
  }
  return self ; 
}

- display: (const NXRect *) aRect ;
{ // I traverses a glist recursively, 
  // translating coord systems and calling
  // drawself as needed. I only draw if
  // my frame intersects visRect, which
  // must be in my ancestor's coord system.
  // If I am the target: I don't translate...
  // the target's origin is 0.0 with
  // respect to the ground view
  // it is drawing into. 
  // If noDraw, then I don't draw myself or
  // any of my subGlyphs. This is used to prevent 
  // the target glyph from drawing into the bGrnd.
  if(NXIntersectsRect(aRect,&frame))
  { NXRect bRect, bounds ;
    bRect.size.width = aRect->size.width ;
    bRect.size.height = aRect->size.height ;
    bounds.origin.x = bounds.origin.y = 0.0 ;
    bounds.size.width = frame.size.width ;
    bounds.size.height = frame.size.height ;
    PSgsave() ;
    if(!flags.isTarget)
    { PStranslate(frame.origin.x, frame.origin.y) ;
      bRect.origin.x = aRect->origin.x - frame.origin.x ;
      bRect.origin.y = aRect->origin.y - frame.origin.y ;
    }
    else
      bRect.origin.x = bRect.origin.y = 0.0 ;
    NXIntersectionRect(&bounds,&bRect) ; // don't allow drawing
    NXRectClip(&bRect) ; // outside of my frame or interRect 
    if(!flags.noDraw) 
    { [self drawSelf: &bRect] ;
      [is display: &bRect] ;
    }
    PSgrestore() ;
  }
  [then display: aRect] ;
  return self ;
}


- drawSelf: (NXRect *) aRect ;
{ // draw my image into whatever is
  // currently focused. Only that part
  // of the image intersecting aRect, in
  // my coord system, needs to be drawn.
  if(flags.isRoot) 
  { PSsetgray(0.8) ;
    PSrectfill(aRect->origin.x,aRect->origin.y,
    aRect->size.width,aRect->size.height) ;
    return self ;
  }
  PSsetgray(0.0) ;
  PSmoveto(0.0,0.0) ;
  PSlineto(0.0,frame.size.height) ;
  PSlineto(frame.size.width,frame.size.height);
  PSlineto(frame.size.width,0.0) ;
  PSlineto(0.0,0.0) ;
  PSlineto(frame.size.width,frame.size.height) ;
  PSstroke() ;
  return self ;
}

- enlist: (Glyph *) aGlyt ;
{ // I am a Glist ; link aGlyt into myself,
  // return the head of the list
  aGlyt->ancestor = ancestor ;
  if([aGlyt precedes: self]) // link before me
  { aGlyt->then = self ;
    return aGlyt ;
  }
  then = [then enlist: aGlyt] ;// ask my neighbour to enlist it
  return self ; 
}


- hitTest: (NXPoint *) aPnt ;
// return id of deepest, leftmost glyph in hierarchy
// which contains aPnt.  aPnt is in my superview's coordinate
// system. Returns nil if no appropriate glyph can be
// found (i.e. not in my frame, nor any of my
// Glist's frames).
{ if(NXPointInRect(aPnt,&frame))
  { id deeperHit ;
    NXPoint thePnt ;
    thePnt.x = aPnt->x - frame.origin.x ; // thePnt = aPnt
    thePnt.y = aPnt->y - frame.origin.y ; // in my coord system
    if(deeperHit = [is hitTest: &thePnt])
      return deeperHit ;
    else
      return self ;
  }
  return [then hitTest: aPnt] ;
}

- (char *) iam ;
{ return iam ;
}

- iam: (char *) str ;
{ strcpy(iam,str) ;
}

- init ;
{ // make sure we are terminated
  [super init];
  is = then = ancestor = [Terminator new] ;  
  // cook up a temporary frame
  frame.origin.x = frame.origin.y = 0.0 ;
  frame.size.width = frame.size.height = 50.0 ;
  return self;
}

- is ;
{ return is ;
}

- is: aGlyph ;
{ return is = aGlyph ;
}

- (BOOL) isTerminator ;
{ return NO ;
}

- moveTo:(float) x :(float)y ;
{ // move my origin to aPnt in my ancestor's
  // coord system.
  frame.origin.x = x ;
  frame.origin.y = y ;
  return self ;
}

- plant: (Glyph *) aGlyt ;
{ // link aGlyt as a subGlyph of myself, i.e.
  // "plant" it as a branch of my subtree
  aGlyt->ancestor = self ;
  if([is isTerminator])
    is = aGlyt ;
  else
    is = [is enlist: aGlyt] ;
  return self ;
}

- (BOOL) precedes: (Glyph *) aGlyph ;
{ // answer YES iff aGlyph should come before
  // me in my Glist. Defaults to left-to-right order
  if([aGlyph isTerminator] ||
    (aGlyph->frame.origin.x > frame.origin.x))
    return YES ;
  else
    return NO ;
}

- sizeTo: (float)width : (float)height ;
{ // changes my size, but does nothing about
  // redisplaying it!
  frame.size.width = width ;
  frame.size.height = height ;
  return self ;
}


- then ;
{ return then ;
}

- then: aGlyph ;
{ return then = aGlyph ;
}

- test: (int) anInt ;
{ // remove when you are satisfied...
  char *name = "none" ;
  if(iam[0] != '\0')
    name = iam ;
  [NXApp printf: "(%d %s %s %s %s)\n",anInt,name,[is iam],
       [then iam], [ancestor iam]] ;
  [is test: anInt + 1] ;
  [then test: anInt] ;
  return self ;
}

- unlink ;
{ // unlink myself (as a Glyt) from the TTree I am a part of.
  // Note: I must be part of a TTree, else bomb!
  if(flags.isRoot) // can't unlink the root glyph!
    return self ;
  if(ancestor->is == self) // the simple case...
    ancestor->is = then ;
  else 
  { Glyph *cursor = ancestor->is ;
    while(cursor->then != self) // find predecessor
      cursor = cursor->then ;
    cursor->then = then ;
  }
  ancestor = then = [Terminator new] ;
  return self ;
}

@end